import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Random;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.basic.Action;
import jade.content.onto.basic.Result;
import jade.core.AID;
import jade.core.Runtime;
import jade.core.Agent;
import jade.core.Location;
import jade.core.ProfileImpl;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.OneShotBehaviour;
import jade.core.behaviours.ParallelBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.core.behaviours.TickerBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.JADEAgentManagement.KillAgent;
import jade.domain.JADEAgentManagement.QueryPlatformLocationsAction;
import jade.domain.mobility.CloneAction;
import jade.domain.mobility.MobileAgentDescription;
import jade.domain.mobility.MobilityOntology;
import jade.domain.mobility.MoveAction;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.proto.states.MsgReceiver;
import jade.wrapper.AgentContainer;
import jade.wrapper.ControllerException;
import jade.wrapper.StaleProxyException;


public class newTestProfiler extends Agent{
	
	ACLMessage superoutMsg=new ACLMessage(ACLMessage.PROXY);
	
	transient private AgentContainer[] home = new AgentContainer[2];
	int MAXPRICE=200;
	
	
	private Location destination;
	private Map<String, Location> locations = new HashMap<String, Location>();
	
	ArrayList<AID> curatorAgent = new ArrayList<AID>();
	private String keyword;

	
	//initial a random price for clones
	protected void afterClone(){
		//MAXPRICE=461;
		MAXPRICE=(new Random().nextInt(450))+51;
		System.out.println("MAX IS: "+MAXPRICE+" "+getAID().getLocalName());
		//init();
	}
	
	protected void afterMove(){
		
	}
	
	protected void init() {
		// Register language and ontology
		getContentManager().registerLanguage(new SLCodec());
		getContentManager().registerOntology(MobilityOntology.getInstance());

		System.out.println("Hallo! Profile agent " + getLocalName()
				+ " is here.");
		char id= getAID().getLocalName().charAt(getAID().getLocalName().length()-1);
		curatorAgent.add(new AID("Clone-Curator"+id, AID.ISLOCALNAME));

		ParallelBehaviour pb = new ParallelBehaviour();
		addBehaviour(new Subscriber());
		addBehaviour(pb);
	}
	
	private class Subscriber extends OneShotBehaviour {

		public void action() {

			// TODO Auto-generated method stub
			ACLMessage msg = new ACLMessage(ACLMessage.SUBSCRIBE);
			msg.addReceiver(curatorAgent.get(0));
			System.out.println("SHAHALABARRRA!");
			send(msg);
			addBehaviour(new Bidder());

		}
	}
	
	private class Bidder extends CyclicBehaviour {

		public void action() {

			// bidders informed in the beginning
			MessageTemplate msg = MessageTemplate
					.MatchPerformative(ACLMessage.INFORM);
			ACLMessage informmsg = receive(msg);

			// auctioneer gives price

			MessageTemplate mt = MessageTemplate
					.MatchPerformative(ACLMessage.CFP);
			ACLMessage cfpmsg = blockingReceive(mt);
			if (cfpmsg != null) {
				// Message received. Process it
				keyword = cfpmsg.getContent();
				try {
					if (((Thingy) cfpmsg.getContentObject()).price < MAXPRICE) {
						ACLMessage reply = cfpmsg.createReply();
						reply.setPerformative(ACLMessage.PROPOSE);

						send(reply);
						System.out.println(getLocalName() + " wants to bid "
								+ keyword);
					} else {
						System.err.println("too expensive!!");
					}
				} catch (UnreadableException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();

				}
				// accept/reject
				if (cfpmsg.getPerformative() == ACLMessage.ACCEPT_PROPOSAL) {
					MessageTemplate mtacc = MessageTemplate
							.MatchPerformative(ACLMessage.ACCEPT_PROPOSAL);
					ACLMessage accmsg = receive(mtacc);
					System.out.print(getLocalName() + " won ");
				}

				else if (cfpmsg.getPerformative() == ACLMessage.REJECT_PROPOSAL) {
					MessageTemplate mtrej = MessageTemplate
							.MatchPerformative(ACLMessage.REJECT_PROPOSAL);
					ACLMessage rejmsg = receive(mtrej);
					System.out.print(getLocalName() + " lost ");
				}

				// no more bidding
				else if (cfpmsg.getPerformative() == ACLMessage.INFORM) {
					MessageTemplate msgend = MessageTemplate
							.MatchPerformative(ACLMessage.INFORM);
					ACLMessage endmsg = blockingReceive(msgend);
					System.out.println("no more bids");
				}

			} else {
				keyword = cfpmsg.getContent();
				ACLMessage reply = cfpmsg.createReply();
				reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
				System.out.println(getLocalName() + " did not understand!");
			}

		}
	}


	protected void setup() {

		doWait(500);
		
		// Register language and ontology
		getContentManager().registerLanguage(new SLCodec());
		getContentManager().registerOntology(MobilityOntology.getInstance());
		
		//initialize
		
			try {
				// Get available locations with AMS
				sendRequest(new Action(getAMS(), new QueryPlatformLocationsAction()));

				// Receive response from AMS
				MessageTemplate mt = MessageTemplate.and(
						MessageTemplate.MatchSender(getAMS()),
						MessageTemplate.MatchPerformative(ACLMessage.INFORM));
				ACLMessage resp = blockingReceive(mt);

				// Get locations from AMS from contentmanager
				ContentElement ce = getContentManager().extractContent(resp);
				Result result = (Result) ce;
				jade.util.leap.Iterator it = result.getItems().iterator();

				// add locationname to our hashmap
				while (it.hasNext()) {
					Location loc = (Location) it.next();
					locations.put(loc.getName(), loc);
					System.out.println(loc.getName());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		
		
		addBehaviour(new ReceiveCommands(this));
		
		//get profile1 clone it and move it to container-1
		if(getAID().getLocalName().endsWith("1"))
			createCloneAndMove(getAID(), "Container-1");
		else
			createCloneAndMove(getAID(), "Container-2");//get profile1 clone it and move it to container-1
			doWait(200);
		init();
	}


	// method that creates clone
	private void createCloneAndMove(AID aid, String destName) {
		// set location
		Location dest = (Location) locations.get(destName);

		// set mobile agent description
		MobileAgentDescription mad = new MobileAgentDescription();
		mad.setName(aid);
		mad.setDestination(dest);
		CloneAction ca = new CloneAction();
		ca.setNewName("Clone-" + aid.getLocalName());
		ca.setMobileAgentDescription(mad);

		// sends a request about making a new copy of this agent
		sendRequest(new Action(getAID(), ca));
	}

	// Moves to agent to the destination
	private void moveAgent(AID aid, String destName) {

		// setlocation
		Location dest = (Location) locations.get(destName);

		// set mobile agent description
		MobileAgentDescription mad = new MobileAgentDescription();
		mad.setName(aid);
		mad.setDestination(dest);
		MoveAction ma = new MoveAction();
		ma.setMobileAgentDescription(mad);
		System.out.println(aid+" "+ma+" "+dest);
		sendRequest(new Action(aid, ma));
	}
	
	//receive commands for actions
	 class ReceiveCommands extends CyclicBehaviour {
		// -----------------------------------------------
		 	private Location destination;
		      ReceiveCommands(Agent a) { super(a); }

			  public void action() {

		         ACLMessage msg = receive(MessageTemplate.MatchPerformative(ACLMessage.REQUEST));

		         if (msg == null) { block(); return; }

			     if (msg.getPerformative() == ACLMessage.REQUEST){

				    try {
					   ContentElement content = getContentManager().extractContent(msg);
					   Concept concept = ((Action)content).getAction();

					   if (concept instanceof CloneAction){

						  CloneAction ca = (CloneAction)concept;
						  String newName = ca.getNewName();
						  Location l = ca.getMobileAgentDescription().getDestination();
						  if (l != null) destination = l;
						  doClone(destination, newName);
					   }
					   else if (concept instanceof MoveAction){

						  MoveAction ma = (MoveAction)concept;
						  Location l = ma.getMobileAgentDescription().getDestination();
						  if (l != null) doMove(destination = l);
					   }
					   else if (concept instanceof KillAgent){

						  doDelete();
					   }
					}
					catch (Exception ex) { ex.printStackTrace(); }
				 }
				 else { System.out.println("Unexpected msg from controller agent"); }
			  }
		   }
	
	
	//send commands for actions
	void sendRequest(Action action) {
		// ---------------------------------

		ACLMessage request = new ACLMessage(ACLMessage.REQUEST);
		request.setLanguage(new SLCodec().getName());
		request.setOntology(MobilityOntology.getInstance().getName());
		try {
			getContentManager().fillContent(request, action);
			request.addReceiver(action.getActor());
			send(request);
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}
}